import requests
import random
import json
import base64
import re
import os
import time
import pyssdb
from pyvirtualdisplay import Display
from squirrel_core.commons.utils.tools import calc_str_md5, upload_file
from playwright.sync_api import sync_playwright
from squirrel_core.commons.utils.get_config import get_config


class ChinaMarathon:
    def __init__(self):
        self.result = ""
        self.extra = ""
        self.bitwise = ""
        self.inpainted = ""
        self.bitwise_result = ""
        self.inpainted_result = ""
        self.error_result = False
        self.success_result = False
        self.b = ""
        self.i = 1
        self.file_path = os.environ.get("FILE_PATH", "/")
        self.base_config = get_config(sections="base")
        self.wx_url = self.base_config.get("wx_url", "")
        self.verify_url = self.base_config.get("verify_url", "")
        self.receive_url = self.base_config.get("receive_url", "")
        self.ssdb_host = self.base_config.get("ssdb_host", "")
        self.ssdb_port = int(self.base_config.get("ssdb_port", 8888))
        self.hash_name = "marathon_captcha"
        self.client = pyssdb.Client(host=self.ssdb_host, port=self.ssdb_port)

    def get_core(self, serialNumber, user_name, card_num, proxy_url=None, proxy_pre=None, logger=None):
        proxy = None
        try:
            url = "http://hxux3cau.user.xiecaiyun.com/api/proxies?action=getJSON&key=NPE1C8212F&count=1&word=&rand=false&norepeat=false&detail=true&ltime=&idshow=true"
            ret = requests.get(url, timeout=10)
            ip_list = json.loads(ret.text).get("result", [])
            if ip_list:
                ip = ip_list[0].get("ip", "")
                port = ip_list[0].get("port", "")
                proxy_str = f"{ip}:{port}"
                proxy_url = f"http://{proxy_str}"
                proxy_pre = f"HxUx3cAu:3KpZTYNS"
        except:
            pass
        if not proxy_pre:
            try:
                huashengdaili_url = "https://getip.huashengdaili.com/servers.php?session=U90348e531009110005--71d1c1c9049a21e6d0d4fb1f1fc828e0&time=5&count=1&type=json&only=1&pw=no&protocol=http&separator=1&iptype=tunnel&format=city,time&dev=web"
                ret = requests.get(huashengdaili_url, timeout=10)
                ip_list = json.loads(ret.text).get("list", [])
                if ip_list:
                    ip = ip_list[0].get("sever", "")
                    port = ip_list[0].get("port", "")
                    proxy_str = f"{ip}:{port}"
                    proxy_url = f"http://{proxy_str}"
            except:
                pass
        if proxy_url:
            if proxy_pre:
                proxy = {
                    "server": proxy_url,
                    "username": proxy_pre.split(":")[0],
                    "password": proxy_pre.split(":")[1]
                }
            else:
                proxy = {
                    "server": proxy_url
                }
        logger.info(f"代理信息：{proxy}")
        display = Display(visible=0, size=(1920, 1080))
        display.start()
        try:
            with sync_playwright() as p:
                browser = p.chromium.launch(headless=False,
                                            # proxy=proxy,
                                            args=[
                                                '--no-sandbox',
                                                '--disable-dev-shm-usage',
                                                '--disable-blink-features=AutomationControlled',
                                                '--disable-features=VizDisplayCompositor,BlinkGenPropertyTrees',
                                                '--disable-web-security',
                                                '--disable-site-isolation-trials',
                                                '--disable-ipc-flooding-protection',
                                                '--disable-renderer-backgrounding',
                                                '--disable-backgrounding-occluded-windows',
                                                '--disable-back-forward-cache',
                                                '--disable-component-extensions-with-background-pages',
                                                '--disable-default-apps',
                                                '--disable-extensions',
                                                '--disable-plugins',
                                                '--disable-translate',
                                                '--disable-sync',
                                                '--no-first-run',
                                                '--no-default-browser-check',
                                                '--start-maximized',
                                                f'--window-size={random.randint(1200, 1920)},{random.randint(800, 1080)}',
                                                '--remote-debugging-port=0',
                                                '--disable-features=AudioServiceOutOfProcess',
                                                '--disable-background-timer-throttling',
                                                '--disable-backgrounding-occluded-windows',
                                                '--disable-breakpad',
                                                '--disable-client-side-phishing-detection',
                                                '--disable-component-update',
                                                '--disable-cookie-encryption',
                                                '--disable-datasaver-prompt',
                                                '--disable-domain-reliability',
                                                '--disable-extensions-http-throttling',
                                                '--disable-hang-monitor',
                                                '--disable-ipc-flooding-protection',
                                                '--disable-popup-blocking',
                                                '--disable-prompt-on-repost',
                                                '--disable-renderer-backgrounding',
                                                '--disable-site-isolation-trials',
                                            ]
                                            )
                user_agents = [
                    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                    'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0'
                ]
                j = 0
                while j <= 3:
                    context = browser.new_context(
                        viewport={'width': random.randint(1200, 1920), 'height': random.randint(800, 1080)},
                        user_agent=random.choice(user_agents),
                        java_script_enabled=True,
                        bypass_csp=True,
                        proxy=proxy,
                        ignore_https_errors=True,
                        extra_http_headers={
                            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
                            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
                            'Accept-Encoding': 'gzip, deflate, br',
                            'Cache-Control': 'no-cache',
                            'Connection': 'keep-alive',
                        }
                    )

                    def on_response(response):
                        # print(response.url)
                        if 'mineRaceScoreWithToken' in response.url:
                            self.result = response.text()
                            # browser.close()

                        if 'inpainted_with_mask' in response.url:
                            self.inpainted = base64.b64encode(response.body()).decode()

                        if 'bitwise_and_result' in response.url:
                            self.bitwise = base64.b64encode(response.body()).decode()
                        if '1r1bsw.captcha-open.aliyuncs.com' in response.url:
                            data = json.loads(response.text())
                            # print(data)
                            if "VerifyResult" in data.get("Result", {}):
                                if data.get("Result", {}).get("VerifyResult", True):
                                    self.success_result = True
                                else:
                                    self.error_result = True
                        # if 'cap_union_new_verify' in response.url:
                        # self.result = response.text()
                        # ticket = json.loads(self.result).get("ticket", "")
                        # randstr = json.loads(self.result).get("randstr", "")
                        # data = {"cardNo":"1111","userName":"aaa","nc_token":ticket,"scene":"1","sessionId":"1","sig":randstr,"cloudType":"tencentyun"}
                        # import requests
                        # proxies = {
                        #     'http': proxy_url,
                        #     # 'https': proxy_url,
                        # }
                        # ss = requests.post("https://api-changzheng.chinaath.com/changzheng-score-center-api/api/app/score/offline/mineRaceScore/token", json=data, proxies=proxies)
                        # token = json.loads(ss.text).get("data", {}).get("timesToken", "")
                        # data = {"timesToken":token,"cardNo":"513029199307285095","competitionName":"","offlineScoreType":None,"userName":"唐华","pageNo":1,"pageQueryFlag":False,"pageSize":9999}
                        # header = {
                        #     "Host": "api-changzheng.chinaath.com",
                        #     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
                        #     "Content-Type": "application/json",
                        #     "Accept": "application/json, text/plain, */*",
                        #     "terminalType": "3",
                        #     "machineCode": "0cb9d8a83362352e5cf44e0095fd0900"
                        # }
                        # ss = requests.post(
                        #     "https://api-changzheng.chinaath.com/changzheng-score-center-api/api/app/score/offline/mineRaceScoreWithToken",
                        #     json=data, proxies=proxies, headers=header)
                        # pass
                        if 'cap_union_prehandle' in response.url:
                            if "请依次点击：" in response.text():
                                response_content = json.loads("".join(re.findall(r"\((.*)\)", response.text())))

                                extra_str = response_content.get("data", {}).get("dyn_show_info", {}).get("instruction", "")
                                self.extra = extra_str.replace("请依次点击：", "").strip().replace(" ", ",")

                    page = context.new_page()

                    def _inject_stealth_script():
                        """注入反检测脚本"""
                        stealth_script = """
                        // 删除自动化特征
                        delete Object.getPrototypeOf(navigator).webdriver;
    
                        // 覆盖chrome运行时
                        window.chrome = {
                            app: {
                                isInstalled: false,
                            },
                            webstore: {
                                onInstallStageChanged: {},
                                onDownloadProgress: {},
                            },
                            runtime: {
                                PlatformOs: {
                                    MAC: 'mac',
                                    WIN: 'win',
                                    ANDROID: 'android',
                                    CROS: 'cros',
                                    LINUX: 'linux',
                                    OPENBSD: 'openbsd',
                                },
                                PlatformArch: {
                                    ARM: 'arm',
                                    X86_32: 'x86-32',
                                    X86_64: 'x86-64',
                                },
                                PlatformNaclArch: {
                                    ARM: 'arm',
                                    X86_32: 'x86-32',
                                    X86_64: 'x86-64',
                                },
                                RequestUpdateCheckStatus: {
                                    THROTTLED: 'throttled',
                                    NO_UPDATE: 'no_update',
                                    UPDATE_AVAILABLE: 'update_available',
                                },
                                OnInstalledReason: {
                                    INSTALL: 'install',
                                    UPDATE: 'update',
                                    CHROME_UPDATE: 'chrome_update',
                                    SHARED_MODULE_UPDATE: 'shared_module_update',
                                },
                                OnRestartRequiredReason: {
                                    APP_UPDATE: 'app_update',
                                    OS_UPDATE: 'os_update',
                                    PERIODIC: 'periodic',
                                },
                            },
                        };
    
                        // 覆盖plugins
                        Object.defineProperty(navigator, 'plugins', {
                            get: () => [
                                {
                                    0: {
                                        type: "application/x-google-chrome-pdf",
                                        suffixes: "pdf",
                                        description: "Portable Document Format",
                                    },
                                    description: 'Portable Document Format',
                                    filename: 'internal-pdf-viewer',
                                    length: 1,
                                    name: 'Chrome PDF Plugin',
                                },
                                {
                                    0: {
                                        type: "application/pdf",
                                        suffixes: "pdf",
                                        description: "Portable Document Format",
                                    },
                                    description: 'Portable Document Format',
                                    filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai',
                                    length: 1,
                                    name: 'Chrome PDF Viewer',
                                },
                            ],
                        });
    
                        // 覆盖languages
                        Object.defineProperty(navigator, 'languages', {
                            get: () => ['zh-CN', 'zh', 'en-US', 'en'],
                        });
    
                        // 覆盖permissions
                        const originalQuery = window.navigator.permissions.query;
                        window.navigator.permissions.query = (parameters) => (
                            parameters.name === 'notifications' ?
                                Promise.resolve({ state: Notification.permission }) :
                                originalQuery(parameters)
                        );
    
                        // 覆盖webgl参数
                        const getParameter = WebGLRenderingContext.getParameter;
                        WebGLRenderingContext.prototype.getParameter = function(parameter) {
                            if (parameter === 37445) {
                                return 'Intel Inc.';
                            }
                            if (parameter === 37446) {
                                return 'Intel Iris OpenGL Engine';
                            }
                            return getParameter(parameter);
                        };
    
                        // 覆盖console.debug
                        console.debug = () => {};
    
                        // 覆盖Notification.permission
                        Object.defineProperty(Notification, 'permission', {
                            get: () => 'default',
                        });
    
                        // 覆盖硬件并发数
                        Object.defineProperty(navigator, 'hardwareConcurrency', {
                            get: () => 8,
                        });
    
                        // 覆盖设备内存
                        Object.defineProperty(navigator, 'deviceMemory', {
                            get: () => 8,
                        });
    
                        // 删除已存在的自动化痕迹
                        Object.defineProperty(window, 'cdc_adoQpoasnfa76pfcZLmcfl_Array', {});
                        Object.defineProperty(window, 'cdc_adoQpoasnfa76pfcZLmcfl_Promise', {});
                        Object.defineProperty(window, 'cdc_adoQpoasnfa76pfcZLmcfl_Symbol', {});
                        """

                        page.add_init_script(stealth_script)

                    _inject_stealth_script()

                    # page = browser.new_page()

                    page.on('response', on_response)

                    try:
                        page.goto("https://www.runchina.org.cn/#/data-score/public-score/list", wait_until="networkidle",
                                  timeout=60000)
                    except:
                        j += 1
                        page.close()
                        continue
                    page.locator('input.el-input__inner').nth(0).type(user_name, delay=100)
                    page.locator('input.el-input__inner').nth(1).type(card_num, delay=100)
                    page.click('xpath=//*[@class="search-button"]', timeout=60000)
                    page.wait_for_selector("#aliyunCaptcha-img-box")
                    # captcha = page.locator("#aliyunCaptcha-img-box")

                    page.wait_for_timeout(3500)
                    r_t = 1
                    while r_t <= 4:
                        logger.info(f"开始第{r_t}次图片碰撞")
                        self.inpainted_result = self.inpainted
                        self.bitwise_result = self.bitwise
                        pic_hash = calc_str_md5(f"{calc_str_md5(self.inpainted_result)}_{calc_str_md5(self.bitwise_result)}")
                        _value = self.client.hget(self.hash_name, pic_hash)
                        distance = ""
                        if _value is None:
                            if r_t == 4:
                                s_t = int(time.time()*1000)
                                logger.info(f"准备发送图片：{s_t}")
                                data = {"id": serialNumber, "verifyOriginalImg": self.inpainted,
                                        "verifyImg": self.bitwise}
                                result = requests.post(self.receive_url,json=data,
                                                       headers={"Content-Type": "application/json"}, timeout=10)
                                logger.info(f"发送结果：{result.text}")
                                d_t = int(time.time() * 1000) - s_t
                                logger.info(f"发送图片完成{int(time.time() * 1000)}，耗时：{d_t}")
                                self.bitwise = ""
                                self.inpainted = ""
                            else:
                                self.bitwise = ""
                                self.inpainted = ""
                                page.click('xpath=//*[@id="aliyunCaptcha-btn-refresh"]')
                                page.wait_for_timeout(3500)
                        else:
                            logger.info(f"使用已有坐标：{_value.decode()}")
                            distance = float(_value.decode())
                            self.bitwise = ""
                            self.inpainted = ""
                            break
                        r_t += 1
                    start_time = int(time.time())
                    while True:
                        if int(time.time() - start_time) <= 60:
                            if not distance:
                                d = self.client.qpop(f"captcha_{serialNumber}")
                                if d:
                                    verify_info = json.loads(d.decode()).get("verifyInfo", "")
                                    leave = json.loads(d.decode()).get("leave", False)
                                    if leave:
                                        break
                                    else:
                                        distance = float(verify_info.split(",")[0])
                                else:
                                    continue
                            move_tag = page.locator('#aliyunCaptcha-sliding-slider')
                            box = move_tag.bounding_box()
                            page.mouse.move(box["x"], box["y"] + box["height"] / 2)
                            time.sleep(0.5)
                            page.mouse.down()

                            step_delay = 0.5
                            t_d = box["x"] + distance * random.uniform(0.0, 0.4)
                            page.mouse.move(t_d, box["y"])
                            time.sleep(step_delay)
                            t_d = box["x"] + distance * random.uniform(0.5, 0.8)
                            page.mouse.move(t_d, box["y"])
                            time.sleep(step_delay)
                            t_d = box["x"] + distance
                            page.mouse.move(t_d, box["y"])
                            time.sleep(0.5)
                            page.mouse.up()
                            try:
                                page.wait_for_selector(".tencent-captcha-dy__watermark-area", timeout=500)
                            except:
                                pass
                            page.wait_for_timeout(3500)
                            if self.error_result:
                                data = {"id": serialNumber, "verifyResult": False}
                                logger.info(f"验证失败[{distance}]:{data}")
                                distance = ""
                                self.i += 1
                                requests.post(self.verify_url, json=data,
                                              headers={"Content-Type": "application/json"}, timeout=10)
                                page.wait_for_timeout(2000)
                                try:
                                    if not all([self.inpainted, self.bitwise]):
                                        page.click('xpath=//*[@id="aliyunCaptcha-btn-refresh"]')
                                        page.wait_for_timeout(1000)
                                except:
                                    pass
                                img_data = {"id": serialNumber, "verifyOriginalImg": self.inpainted, "verifyImg": self.bitwise}

                                self.inpainted_result = self.inpainted
                                self.bitwise_result = self.bitwise
                                s_t = int(time.time() * 1000)
                                logger.info(f"准备发送图片：{s_t}")
                                result = requests.post(self.receive_url, json=img_data,
                                                       headers={"Content-Type": "application/json"}, timeout=10)
                                logger.info(f"发送结果：{result.text}")
                                d_t = int(time.time() * 1000) - s_t
                                logger.info(f"发送图片完成{int(time.time() * 1000)}，耗时：{d_t}")
                                self.error_result = False
                                self.bitwise = ""
                                self.inpainted = ""
                                continue
                            if self.success_result:
                                pic_hash = calc_str_md5(f"{calc_str_md5(self.inpainted_result)}_{calc_str_md5(self.bitwise_result)}")
                                result_code = self.client.hset(self.hash_name, pic_hash, str(distance))
                                if result_code == 1:
                                    logger.info("坐标存储成功")
                                else:
                                    logger.info("坐标已经存在")
                                data = {"id":serialNumber, "verifyResult":True}
                                logger.info(f"验证成功[{distance}]:{data}")
                                requests.post(self.verify_url,json=data,
                                              headers={"Content-Type": "application/json"}, timeout=10)
                                page.wait_for_timeout(3500)
                                break
                        else:
                            data = {"id": serialNumber, "verifyResult": False, "finish": True}
                            logger.info(f"重试结束:{data}")
                            requests.post(self.verify_url, json=data,
                                          headers={"Content-Type": "application/json"}, timeout=10)
                            break
                    break
            return self.result
        except Exception as e:
            logger.info(f"错误: {e}")
            return self.result
        finally:
            try:
                if browser:
                    browser.close()
            except:
                pass
            try:
                if display:
                    display.stop()
            except:
                pass
            try:
                self.client.qclear(f"captcha_{serialNumber}")
                self.client.disconnect()
            except:
                pass
            return self.result

# a = ChinaMarathon().get_core("唐华", "513029199307285095")
# print(a)

# c = pyssdb.Client(host="1.14.96.163", port=8888)
# while True:
#     user_dada = c.qpop("marathon")
#     if user_dada:
#         user_dada = json.loads(user_dada)
#         print(user_dada)
#         serialNumber = user_dada.get("serialNumber", "")
#         webType = user_dada.get("webType", "")
#         crawlerType = user_dada.get("crawlerType", "")
#         user_name = user_dada.get("user_name", "唐华")
#         card_num = user_dada.get("card_num", "513029199307285095")
#         proxy = user_dada.get("proxy_url", "219.159.100.253:2324")
#         # huashengdaili_url = "https://getip.huashengdaili.com/servers.php?session=U90348e531009110005--71d1c1c9049a21e6d0d4fb1f1fc828e0&time=5&count=1&type=json&only=1&pw=no&protocol=http&separator=1&iptype=tunnel&format=city,time&dev=web"
#         # ret = requests.get(huashengdaili_url, timeout=10)
#         # ip_list = json.loads(ret.text).get("list", [])
#         # ip = ip_list[0].get("sever", "")
#         # port = ip_list[0].get("port", "")
#         # proxy = f"{ip}:{port}"
#         # proxy = "171.110.82.48:2324"
#         proxy_url = f"http://{proxy}"
#         print(proxy_url)
#         a=ChinaMarathon().get_core(serialNumber,user_name, card_num, proxy_url)
#         print(a)
#         result_dict = {"serialNumber": serialNumber, "webType": webType, "crawlerType": crawlerType, "data": a,
#                        "raceId": "", "userId": ""}
#         resp = requests.post("http://118.24.189.106:9905/api/scrapy/dealData", json=result_dict, headers={"Content-Type": "application/json"})
#         content = resp.text
#         print(f"发送结果：{content}")
#     else:
#         print("队列为空，等待10s")
#         time.sleep(2)